const h = (tag, props, children) => {
   // vnode --->javascript 对象--->{}
   return {
     tag,
     props,
     children
   }
}

// 我们需要拿到  vnode 挂载到真实 DOM 上 也就是我们这里的 <div id="tutu"> </div>
const mount = (vnode,container) => {
   // node  -->element
   // 先创建出了真实的元素,并在vnode上保留 这个真实 DOM
   const el = vnode.el = document.createElement(vnode.tag)
   
   // 处理props
   if (vnode.props) {
     for (const key in vnode.props) {
        const value = vnode.props[key]
        // 这里是对于 props 是为函数的情况进行处理
        if(key.startsWith("on")) {
          el.addEventListener(key.slice(2).toLocaleLowerCase(), value)
        } else {
          el.setAttribute(key, value)
        }
     }
   }
   // 处理 子节点   这里只对于 字符串跟数组类型进行了处理
   if(vnode.children) {
     //   数组情况
     if (typeof vnode.children !== "string") {
      vnode.children.forEach(item => {
        // 因为这里的  [children] 数组里 又是一个个h()函数
        // 所以进行 递归  对 item 里面进行mout处理 此时挂载的是当前 VNode 元素上
        mount(item, el)
       })
     } else {
     //  字符串情况
     el.textContent  = vnode.children
    }
   } 
   // 将 el 挂载到container 上
   container.appendChild(el)
}

// 传递进来两个VNode
const patch = (n1, n2) => {
  // 1: 首先先 判断下两个 VNode 的tag 是否相同, 相同的话就直接暴力移除旧的
  if ( n1.tag !== n2.tag) {
    //  移除 旧 VNode 的父元素  
    const n1ElParent = n1.el.parentElement;
    n1ElParent.removeChild(n1.el);
    //  将 新 VNode 挂在 n1的父元素上
    mount(n2,n1ElParent)
  } else {
    //取出 element 对象 并且在 n2 中进行保存
    const el = n2.el = n1.el 
    // 2:   处理props
    const oldProps = n1.props || {}
    const newProps = n2.props || {}
    //  获取所有的 newProps
    for (const key in newProps) {
      const oldValue = oldProps[key]
      const newValue = newProps[key]
      if ( newValue !== oldValue ) {
        if ( key.startsWith("on") ) {
          el.addEventListener(key.slice(2).toLocaleLowerCase(), newValue)
        } else {
          el.setAttribute(key, newValue)
        }
      }
    }
    // 删除就的props
    for (const key in oldProps) {
      if (key.startsWith("on")) { // 对事件监听的判断
        const value = oldProps[key];
        el.removeEventListener(key.slice(2).toLowerCase(), value)
      }
      if (!(key in newProps)) {
        el.removeAttribute(key);
      }
    }


    //处理children
    const oldChildren = n1.children || []
    const newChildren = n2.children || []
    // 如果新vnode  的children 是字符串 类型  就直接进行赋值
    if( typeof newChildren === "string") {
      //  edge case 边界判断
      if( typeof oldChildren === "string") {
        if ( oldChildren !== newChildren ) {
          el.textContent = newChildren
        }
      } else {
        el.innerHTML = newChildren
      }
    } else {
      // 新vnode 是数组  旧vnode是字符串的情况
      if ( typeof oldChildren === "string") {
        el.innerHTML = ""
        newChildren.forEach((item) => {
          mount(item, el)
        })
      } else {
        //  都是数组的情况
        // 对于有相同节点进行patch 操作
        // 这里处理没有 key 的情况下
        // 1 先取出 更短的长度进行遍历 进行diff算法
        const commonLength = Math.min(oldChildren.length, newChildren.length)
        for(let i = 0; i < commonLength; i ++) {
          // 将公共 部分 进行 patch()
          patch(oldChildren[i], newChildren[i])
        }
        //  新的节点 长度大于 旧的长度 是将多余的部分进行挂载操作  mount()
        if( newChildren.length > oldChildren.length) {
          newChildren.slice(oldChildren.length).forEach(item => {
            mount(item, el)
          })
        }
        //  新的节点 小于旧的节点长度,  将 旧的节点 进行移除操作  removechild()
        if( newChildren.length < oldChildren.length) {
          oldChildren.slice(newChidlren.length).forEach(item => {
            el.removeChild(item.el)
          })
        }
      }
    }

  }
}